using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;
using Microsoft.Win32;

namespace ScottLane.VideoInbox
{
    /// <summary>
    /// Provides access to all of the application configuration settings.
    /// </summary>
    public sealed class ConfigurationSettings
    {
        private static readonly ConfigurationSettings instance = new ConfigurationSettings();
        private static string installationDirectory;
        private static string fileName;

        #region Constructor

        /// <summary>
        /// Initializes the configuration instance by loading the configuration settings from disk.
        /// </summary>
        static ConfigurationSettings()
        {
            installationDirectory = Registry.LocalMachine.OpenSubKey(@"Software\Scott Lane\Video Inbox").GetValue("Installation Directory").ToString();
            fileName = Path.Combine(installationDirectory, "Configuration.xml");

            if (File.Exists(fileName))
            {
                using (FileStream stream = new FileStream(fileName, FileMode.Open))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationSettings));
                    instance = (ConfigurationSettings)serializer.Deserialize(stream);
                }
            }

            instance.DownloadQueuePollingInterval = 5000;
            instance.NotificationQueuePollingInterval = 5000;
            instance.PlaylistDownloadLimit = 10;
            instance.DownloadingVideoFileName = Path.Combine(installationDirectory, "Downloading.wmv");
            instance.NotDownloadedVideoFileName = Path.Combine(installationDirectory, "Not Downloaded.wmv");
            instance.InboxPath = @"M:\Videos\ Inbox";
            instance.NotificationTimeout = 10;
            instance.VideoSources = new List<VideoSource>();
            instance.SourceCheckStartTime = new TimeSpan(0);
            instance.SourceCheckEndTime = new TimeSpan(12, 0, 0);
            instance.SourceCheckSleepInterval = 3600000;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the current configuration settings instance.
        /// </summary>
        public static ConfigurationSettings Instance
        {
            get { return instance; }
        }

        private TimeSpan _sourceCheckStartTime;

        /// <summary>
        /// Gets or sets the starting time for checking sources for videos.
        /// </summary>
        [XmlIgnore]
        public TimeSpan SourceCheckStartTime
        {
            get { return _sourceCheckStartTime; }
            set { _sourceCheckStartTime = value; }
        }

        /// <summary>
        /// Gets or sets a serializable value of the starting time for checking sources for video.
        /// </summary>
        [XmlElement("SourceCheckStartTime")]
        public string SourceCheckStartTimeString
        {
            get { return _sourceCheckStartTime.ToString(); }
            set { _sourceCheckStartTime = TimeSpan.Parse(value); }
        }

        private TimeSpan _sourceCheckEndTime;

        /// <summary>
        /// Gets or sets the end time for checking sources for videos.
        /// </summary>
        [XmlIgnore]
        public TimeSpan SourceCheckEndTime
        {
            get { return _sourceCheckEndTime; }
            set { _sourceCheckEndTime = value; }
        }

        /// <summary>
        /// Gets or sets a serializable value of the end time for checking sources for video.
        /// </summary>
        [XmlElement("SourceCheckEndTime")]
        public string SourceCheckEndTimeString
        {
            get { return _sourceCheckEndTime.ToString(); }
            set { _sourceCheckEndTime = TimeSpan.Parse(value); }
        }

        private int _sourceCheckSleepInterval;

        /// <summary>
        /// The time between checking all sources for new videos in milliseconds.
        /// </summary>
        public int SourceCheckSleepInterval
        {
            get { return _sourceCheckSleepInterval; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException("The source check sleep interval must be greater than 0", "value");
                }

                _sourceCheckSleepInterval = value;
            }
        }

        private int _downloadQueuePollingInterval;

        /// <summary>
        /// Gets or sets the download queue polling interval in milliseconds.
        /// </summary>
        public int DownloadQueuePollingInterval
        {
            get { return _downloadQueuePollingInterval; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException("The download queue polling interval must be greater than 0", "value");
                }

                _downloadQueuePollingInterval = value;
            }
        }

        private int _notificationQueuePollingInterval;

        /// <summary>
        /// Gets or sets the notification queue polling interval in milliseconds.
        /// </summary>
        public int NotificationQueuePollingInterval
        {
            get { return _notificationQueuePollingInterval; }
            set
            {
                if (value <= 1000)
                {
                    throw new ArgumentOutOfRangeException("The notification queue polling interval must be greater than 1000", "value");
                }

                _notificationQueuePollingInterval = value;
            }
        }

        private int _playlistDownloadLimit;

        /// <summary>
        /// Gets or sets the maximum number of files to be downloaded in a playlist before the user is warned.
        /// </summary>
        public int PlaylistDownloadLimit
        {
            get { return _playlistDownloadLimit; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException("The playlist download limit must be greater than 0", "value");
                }

                _playlistDownloadLimit = value;
            }
        }

        private string _downloadingVideoFileName;

        /// <summary>
        /// Gets or sets the file name of the video that is displayed if a video is being downloaded.
        /// </summary>
        public string DownloadingVideoFileName
        {
            get { return _downloadingVideoFileName; }
            set
            {
                if (!File.Exists(value))
                {
                    throw new ArgumentException("The downloading video path does not exist", "value");
                }

                _downloadingVideoFileName = value;
            }
        }

        /// <summary>
        /// Gets or sets the file name of the video that is displayed if a video has not been downloaded.
        /// </summary>
        private string _notDownloadedVideoFileName;

        public string NotDownloadedVideoFileName
        {
            get { return _notDownloadedVideoFileName; }
            set
            {
                if (!File.Exists(value))
                {
                    throw new ArgumentException("The not downloaded video path does not exist", "value");
                }

                _notDownloadedVideoFileName = value;
            }
        }

        private string _inboxPath;

        /// <summary>
        /// Gets or sets the path of the video inbox that contains shortcuts to all new videos.
        /// </summary>
        public string InboxPath
        {
            get { return _inboxPath; }
            set
            {
                if (!Directory.Exists(value))
                {
                    throw new ArgumentException("The inbox path does not exist", "value");
                }

                _inboxPath = value;
            }
        }

        private int _notificationTimeout;

        /// <summary>
        /// Gets or sets the timeout of all Media Center notification messages.
        /// </summary>
        public int NotificationTimeout
        {
            get { return _notificationTimeout; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException("The notification timeout must be greater than 0", "value");
                }

                _notificationTimeout = value;
            }
        }

        private List<VideoSource> _videoSources;

        /// <summary>
        /// Gets or sets the video sources.
        /// </summary>
        public List<VideoSource> VideoSources
        {
            get { return _videoSources; }
            set { _videoSources = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Backs up and saves the configuration settings.
        /// </summary>
        public void Save()
        {
            FileInfo configurationFile = new FileInfo(fileName);
            FileInfo backupFile = new FileInfo(Path.ChangeExtension(fileName, ".bak"));

            try
            {
                using (FileStream stream = configurationFile.OpenWrite())
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationSettings));
                    serializer.Serialize(stream, this);
                }

                if (backupFile.Exists)
                {
                    backupFile.Delete();
                }

                configurationFile.CopyTo(backupFile.FullName);
            }
            catch (Exception ex)
            {
                if (File.Exists(configurationFile.FullName))
                {
                    configurationFile.Delete();
                }

                if (backupFile.Exists)
                {
                    backupFile.CopyTo(configurationFile.FullName);
                }

                throw (ex);
            }
        }

        #endregion
    }
}
